package com.czkevin.biliwsclient;

import com.alibaba.fastjson.JSONObject;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

public class BiliLiveClient extends WebSocketClient {

    public static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0";

    private static final URI REMOTE_URI;
    private static final Map<String, String> HEADER = new HashMap<>();

    static {
        URI s;
        try {
            s = new URI("wss://ks-live-dmcmt-bj6-pm-02.chat.bilibili.com/sub");
        } catch (URISyntaxException e) {
            e.printStackTrace();
            s = null;
        }
        REMOTE_URI = s;
        HEADER.put("Origin", "https://live.bilibili.com");
        HEADER.put("User-Agent", DEFAULT_USER_AGENT);
    }

    private final long room;
    private final String token;

    private Thread heartbeats;

    private BiliPacketCallback callback;

    public BiliLiveClient(URI remoteUri, long room, String token, BiliPacketCallback callback) {
        super(remoteUri, HEADER);
        this.room = room;
        this.token = token;
        this.callback = callback;
    }

    public BiliLiveClient(long room, String token, BiliPacketCallback callback) {
        super(REMOTE_URI, HEADER);
        this.room = room;
        this.token = token;
        this.callback = callback;
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        // System.out.println("Connection opened: " + serverHandshake.getHttpStatus());
        callback.onConnected();

        if(heartbeats != null){
            try {heartbeats.interrupt(); } catch (Exception e) { }
            heartbeats = null;
        }
        heartbeats = new Thread(() -> {
            while(isOpen() && !isClosed()) {
                try {
                    Thread.sleep(29000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                send(new BiliPacket(2, 0).serialize());
            }
        });
        heartbeats.start();

        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        JSONObject login = new JSONObject();
        login.put("uid", 0);
        login.put("roomid", room);
        login.put("protover", 3);
        login.put("platform", "web");
        login.put("clientver", "1.10.6");
        login.put("type", 2);
        login.put("key", token);
        send(new BiliPacket(7, 0, login.toJSONString()).serialize());
    }

    @Override
    public void onMessage(ByteBuffer bytes) {
        byte[] p = new byte[bytes.remaining()];
        bytes.get(p, 0, p.length);
        BiliPacket[] packets = BiliPacket.deserialize(p);
        for(BiliPacket packet : packets) {
            /*if(packet.data != null) {
                System.out.println("+++ received: " + new String(packet.data, StandardCharsets.UTF_8));
            }*/
            try {
                callback.onReceive(packet);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onMessage(String s) {

    }

    @Override
    public void onClose(int i, String s, boolean b) {
        if(heartbeats != null) {
            try {heartbeats.interrupt(); } catch (Exception e) { }
            heartbeats = null;
        }
        callback.onClose(null);
    }

    @Override
    public void onError(Exception e) {
        try {close();}catch (Exception ex) {ex.printStackTrace();}
        callback.onClose(e);
    }

    public interface BiliPacketCallback {
        void onConnected();

        void onReceive(BiliPacket packet);

        void onClose(Exception ex);
    }
}
